/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package edu.lnu.ums.treestructure.impl;

import edu.lnu.ums.dal.IUMSObjectDAO;
import edu.lnu.ums.dal.factories.FactoriesCache;
import edu.lnu.ums.entities.core.UMSObject;
import edu.lnu.ums.treestructure.ITreeStructure;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.ejb.Stateful;
import javax.persistence.EntityManagerFactory;

@Stateful
public class TreeStructure implements ITreeStructure {

    private static final String DELIMETER = " ";
    private static final int FACTORY_NAME_PART = 0;
    private static final int ID_PART = 1;
    @EJB(mappedName = "UMS/UMSObjectDAO/local")
    private IUMSObjectDAO umsObjectDAO;
    private TreeNode root;
    private Set<String> clickedIds;

    public TreeStructure() {
    }

    @PostConstruct
    public void init() {
        UMSObject obj = umsObjectDAO.getRoot(FactoriesCache.getInstance().getDefaultFactory());
        root = new TreeNode(getStringKey(obj), obj);
        clickedIds = new LinkedHashSet<String>();
        clickedIds.add(getStringKey(obj));
        loadTwoNextGenerations(obj);
    }

    private void loadNextGeneration(UMSObject obj) {
        try {
            TreeNode node = root.getChildById(getStringKey(obj));

            if (node == null) {
                clickedIds.remove(getStringKey(obj));
                return;
            }

            List<UMSObject> children = umsObjectDAO.getChildren(obj);

            for (UMSObject child : children) {
                if (!node.containIdAmongChildren(getStringKey(child))) {
                    TreeNode newChildNode = new TreeNode(getStringKey(child), child);
                    node.getChildren().add(newChildNode);
                    newChildNode.setParent(node);
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }

    }

    private void loadTwoNextGenerations(UMSObject obj) {
        loadNextGeneration(obj);
        TreeNode node = root.getChildById(getStringKey(obj));

        if (node == null) {
            clickedIds.remove(getStringKey(obj));
            return;
        }

        for (TreeNode child : node.getChildren()) {
            loadNextGeneration(child.getData());
        }
    }

    @Override
    public void makeClick(UMSObject object) {
        if (!clickedIds.contains(getStringKey(object))) {
            loadTwoNextGenerations(object);
            clickedIds.add(getStringKey(object));
        }
    }

    @Override
    public void refreshTree() {
        UMSObject obj = umsObjectDAO.getRoot(FactoriesCache.getInstance().getDefaultFactory());
        root = new TreeNode(getStringKey(obj), obj);

        for (String id : new LinkedHashSet<String>(clickedIds)) {
            String[] pair = id.split(DELIMETER);
            EntityManagerFactory factory = FactoriesCache.getInstance().getFactory(pair[FACTORY_NAME_PART]);
            if (factory != null) {
                Long objectId = Long.parseLong(pair[ID_PART]);
                UMSObject object = umsObjectDAO.getById(factory, objectId);
                if (object != null) {
                    loadTwoNextGenerations(object);
                }
            }
        }
    }

    @Override
    public TreeNode getRoot() {
        return root;
    }

    private String getStringKey(UMSObject object) {
        if (object == null) {
            throw new IllegalArgumentException();
        }

        return FactoriesCache.getInstance().getNameByEntityManagerFactory(object.getFactory())
                + DELIMETER + String.valueOf(object.getId());

    }

    @Override
    public void refreshNode(UMSObject object) {
        TreeNode node = root.getChildById(getStringKey(object));
        node.setName(object.getNodeName());
        node.setData(object);
    }

    @Override
    public void removeNode(UMSObject object) {
        TreeNode node = root.getChildById(getStringKey(object));
        node.getParent().getChildren().remove(node);
    }

    @Override
    public void addAsChild(UMSObject parent, UMSObject child) {
        TreeNode parentNode = root.getChildById(getStringKey(parent));
        TreeNode childNode = new TreeNode(getStringKey(child), child);
        parentNode.getChildren().add(childNode);
        childNode.setParent(parentNode);
    }
}
